package mirrormonkey.framework.test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import mirrormonkey.commons.graph.SyncGeometry;
import mirrormonkey.core.test.entities.ConstructorTestBox;
import mirrormonkey.core.test.entities.ConstructorTestBox.CalledConstructor;
import mirrormonkey.framework.ConnectionInfo;
import mirrormonkey.framework.entity.SyncEntity;
import mirrormonkey.framework.test.application.ClientTestApplication;
import mirrormonkey.framework.test.application.ServerTestApplication;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.BeforeClass;

import com.jme3.math.Vector3f;
import com.jme3.network.HostedConnection;
import com.jme3.system.JmeContext;

public class JUnitTestMultiClient extends JUnitTest {

	public static final int CLIENT_COUNT = 5;

	public static ServerTestApplication serverApplication;

	public static ClientTestApplication[] clientApplications;

	@BeforeClass
	public static void setUpClass() throws Throwable {
		serverApplication = generateServer();
		clientApplications = new ClientTestApplication[CLIENT_COUNT];
		clientApplications[0] = generateClient();
		for (int i = 1; i < clientApplications.length; i++) {
			clientApplications[i] = generateClient(JmeContext.Type.Headless);
		}
	}

	@AfterClass
	public static void tearDownClass() {
		serverApplication.stop();
		for (ClientTestApplication i : clientApplications) {
			i.stop();
		}
	}

	@After
	public void tearDown() {
		serverApplication.clear();
		ensureMessageProcessing();
		for (ClientTestApplication i : clientApplications) {
			i.clear();
		}
	}

	public static ClientTestApplication getApplication() {
		return getApplication(0);
	}

	public static ClientTestApplication getApplication(int clientId) {
		return clientApplications[clientId];
	}

	public static ConnectionInfo serverInfo(int clientId) {
		return serverApplication.coreModule.getData(getConnection(clientId));
	}

	public static ConnectionInfo clientInfo(int clientId) {
		return getApplication(clientId).coreModule
				.getData(getApplication(clientId).client);
	}

	public static HostedConnection getConnection() {
		return getConnection(0);
	}

	public static HostedConnection getConnection(int clientId) {
		return serverApplication.server
				.getConnection(getApplication(clientId).client.getId());
	}

	public static void ensureMessageProcessing() {
		sleep(1000);
		serverApplication.ensureUpdate();
		for (ClientTestApplication i : clientApplications) {
			i.ensureUpdate();
		}
		sleep(1000);
		serverApplication.ensureUpdate();
		for (ClientTestApplication i : clientApplications) {
			i.ensureUpdate();
		}
	}

	public static final void assertUnknown(SyncEntity serverSide,
			ClientTestApplication client) {
		assertTrue(serverSide.getData() == null
				|| !client.getClientData(serverSide).isRegistered());
	}

	public static final void assertClasses(SyncEntity serverSide) {
		assertClasses(serverSide, serverSide.getClass());
	}

	public static final void assertClasses(SyncEntity serverSide,
			Class<? extends SyncEntity> clientSide) {
		assertClasses(serverSide, getApplication(), clientSide);
	}

	public static final void assertClasses(SyncEntity serverSide,
			ClientTestApplication client, Class<? extends SyncEntity> clientSide) {
		assertEquals(clientSide, client.getClientData(serverSide).getEntity()
				.getClass());
	}

	public static final void assertConstr(SyncEntity serverSide,
			CalledConstructor constr) {
		assertConstr(serverSide, getApplication(), constr);
	}

	public static final void assertConstr(SyncEntity serverSide,
			ClientTestApplication client, CalledConstructor constr) {
		((ConstructorTestBox) client.getClientData(serverSide).getEntity())
				.assertConstructorCalled(constr);
	}

	public static final void assertLocalTranslation(SyncGeometry serverSide) {
		assertLocalTranslation(serverSide, serverSide.getLocalTranslation());
	}

	public static final void assertLocalTranslation(SyncGeometry serverSide,
			Vector3f localTranslation) {
		assertLocalTranslation(serverSide, getApplication(), localTranslation);
	}

	public static final void assertLocalTranslation(SyncGeometry serverSide,
			ClientTestApplication client) {
		((ConstructorTestBox) client.getClientData(serverSide).getEntity())
				.assertLocalTranslation(serverSide.getLocalTranslation());
	}

	public static final void assertLocalTranslation(SyncGeometry serverSide,
			ClientTestApplication client, Vector3f localTranslation) {
		((ConstructorTestBox) client.getClientData(serverSide).getEntity())
				.assertLocalTranslation(localTranslation);
	}

}
